/*
  +----------------------------------------------------------------------+
  | PHP Version 7                                                        |
  +----------------------------------------------------------------------+
  | Copyright (c) 1997-2018 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.01 of the PHP license,      |
  | that is bundled with this package in the file LICENSE, and is        |
  | available through the world-wide-web at the following url:           |
  | http://www.php.net/license/3_01.txt                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Author:                                                              |
  +----------------------------------------------------------------------+
*/

/* $Id$ */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_scarecrow.h"
#include "qrencode.h"    
#include "base64.h"
/* If you declare any globals in php_scarecrow.h uncomment this:
ZEND_DECLARE_MODULE_GLOBALS(scarecrow)
*/

/* True global resources - no need for thread safety here */
static int le_scarecrow;
zend_class_entry *scarecrowPtr=NULL;

//规范方法参数（可以不用）
ZEND_BEGIN_ARG_INFO_EX(scarecrow_fucinfo_name, 0, 0, 1)
ZEND_ARG_INFO(0, name)
ZEND_END_ARG_INFO()


/* {{{ PHP_INI
 */
/* Remove comments and fill if you need to have entries in php.ini
PHP_INI_BEGIN()
    STD_PHP_INI_ENTRY("scarecrow.global_value",      "42", PHP_INI_ALL, OnUpdateLong, global_value, zend_scarecrow_globals, scarecrow_globals)
    STD_PHP_INI_ENTRY("scarecrow.global_string", "foobar", PHP_INI_ALL, OnUpdateString, global_string, zend_scarecrow_globals, scarecrow_globals)
PHP_INI_END()
*/
/* }}} */
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY("scarecrow.name", "scarecrow", PHP_INI_ALL, OnUpdateString, name, zend_scarecrow_globals, scarecrow_globals)
STD_PHP_INI_ENTRY("scarecrow.isshuaige", "yes", PHP_INI_ALL, OnUpdateString, isshuaige, zend_scarecrow_globals, scarecrow_globals)
STD_PHP_INI_ENTRY("scarecrow.sex", "1", PHP_INI_ALL, OnUpdateLong, sex, zend_scarecrow_globals, scarecrow_globals)
STD_PHP_INI_ENTRY("scarecrow.age", "23", PHP_INI_ALL, OnUpdateLong, age, zend_scarecrow_globals, scarecrow_globals)
STD_PHP_INI_ENTRY("scarecrow.address", "ChongQing", PHP_INI_ALL, OnUpdateString, address, zend_scarecrow_globals, scarecrow_globals)
PHP_INI_END()

/* Remove the following function when you have successfully modified config.m4
   so that your module can be compiled into PHP, it exists only for testing
   purposes. */

void printZval(zval z)
{
	switch (Z_TYPE(z))
	{
	case IS_NULL:
		php_printf("NULL");
		break;
	case IS_LONG:
		php_printf("%f", Z_LVAL(z));
		break;
	case IS_DOUBLE:
		php_printf("%f",Z_DVAL(z));
		break;
	case IS_STRING:
		php_printf("str:%s len:%d", Z_STRVAL(z), Z_STRLEN(z));
		break;
	case IS_ARRAY:
		php_printf("Array");
		break;
	case IS_OBJECT:
		php_printf("Object");
		break;
	default:
		php_printf("Error type!");
		break;
	}
}

/* Every user-visible function in PHP should document itself in the source */
/* {{{ proto string confirm_scarecrow_compiled(string arg)
   Return a string to confirm that the module is compiled in */
PHP_FUNCTION(showAuthor)
{
	RETURN_STRING("Scarecrow");
}

int showQrencodes(char *str, char *filePathName)
{
	char *szSourceSring = str; 
	unsigned int    unWidth, x, y, l, n, unWidthAdjusted, unDataBytes;
	unsigned char*  pRGBData, *pSourceData, *pDestData;
	QRcode*         pQRC;
	FILE*           f;
	// Compute QRCode
	if (pQRC = QRcode_encodeString(szSourceSring, 0, QR_ECLEVEL_H, QR_MODE_8, 1))
	{
		unWidth = pQRC->width;
		unWidthAdjusted = unWidth * 8 * 3;
		if (unWidthAdjusted % 4)
			unWidthAdjusted = (unWidthAdjusted / 4 + 1) * 4;
		unDataBytes = unWidthAdjusted * unWidth * 8;
		// Allocate pixels buffer
		if (!(pRGBData = (unsigned char*)malloc(unDataBytes)))
		{
			//php_printf("Out of memory");
			free(pRGBData);
			QRcode_free(pQRC);
			return 1;
		}
		// Preset to white
		memset(pRGBData, 0xff, unDataBytes);
		// Prepare bmp headers
		BITMAPFILEHEADER kFileHeader;
		kFileHeader.bfType = 0x4d42;  // "BM"
		kFileHeader.bfSize = sizeof(BITMAPFILEHEADER) +
			sizeof(BITMAPINFOHEADER) +
			unDataBytes;
		kFileHeader.bfReserved1 = 0;
		kFileHeader.bfReserved2 = 0;
		kFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) +
			sizeof(BITMAPINFOHEADER);
		BITMAPINFOHEADER kInfoHeader;
		kInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
		kInfoHeader.biWidth = unWidth * 8;
		kInfoHeader.biHeight = -((int)unWidth * 8);
		kInfoHeader.biPlanes = 1;
		kInfoHeader.biBitCount = 24;
		kInfoHeader.biCompression = BI_RGB;
		kInfoHeader.biSizeImage = 0;
		kInfoHeader.biXPelsPerMeter = 0;
		kInfoHeader.biYPelsPerMeter = 0;
		kInfoHeader.biClrUsed = 0;
		kInfoHeader.biClrImportant = 0;
		// Convert QrCode bits to bmp pixels
		pSourceData = pQRC->data;
		for (y = 0; y < unWidth; y++)
		{
			pDestData = pRGBData + unWidthAdjusted * y * 8;
			for (x = 0; x < unWidth; x++)
			{
				if (*pSourceData & 1)
				{
					for (l = 0; l < 8; l++)
					{
						for (n = 0; n < 8; n++)
						{
							*(pDestData + n * 3 + unWidthAdjusted * l) = 0;
							*(pDestData + 1 + n * 3 + unWidthAdjusted * l) = 0;
							*(pDestData + 2 + n * 3 + unWidthAdjusted * l) = 0;
						}
					}
				}
				pDestData += 3 * 8;
				pSourceData++;
			}
		}
		// Output the bmp file
		if (!(fopen_s(&f, filePathName, "wb")))
		{
			fwrite(&kFileHeader, sizeof(BITMAPFILEHEADER), 1, f);
			fwrite(&kInfoHeader, sizeof(BITMAPINFOHEADER), 1, f);
			fwrite(pRGBData, sizeof(unsigned char), unDataBytes, f);
			fclose(f);
		}
		else
		{
			//php_printf("Unable to open file");
			free(pRGBData);
			QRcode_free(pQRC);
			return 2;
		}
		// Free data
		free(pRGBData);
		QRcode_free(pQRC);
	}
	else
	{
		//php_printf("NULL returned");
		return 3;
	}

	return 0;
}

PHP_FUNCTION(createQrencode)
{
	int LEN = 3,state=0;
	char *arg, *isBaoCun="0",*filePath="./temp.bmp";
	size_t arg_len,t_eol,filePathLen;
	int b=0;
	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|ss", &arg, &arg_len,&isBaoCun, &t_eol,&filePath,&filePathLen) == FAILURE) {
		return;
	}

	if (strcmp(isBaoCun, "0") == 0) {
		b = 0;
	}
	else {
		b = 1;
	}
	state = showQrencodes(arg, filePath);
	if (state == 0) {
		if (b == 0) {
			FILE *fp = NULL;
			unsigned int size;
			char *buffer;
			char *buffer1;
			size_t result;
			char *ret1;
			unsigned int length;

			fp = fopen(filePath, "rb");
			if (NULL == fp)
			{
				RETURN_NULL();
			}

			fseek(fp, 0L, SEEK_END);
			size = ftell(fp);
			fseek(fp, 0L, SEEK_SET);
			buffer = (char *)emalloc(size * 1.5);
			if (NULL == buffer)
			{
				RETURN_NULL();
			}

			result = fread(buffer, 1, size, fp);
			if (result != size)
			{
				RETURN_NULL();
			}
			fclose(fp);
			buffer1 = (char *)emalloc(size * 1.5);
			if (NULL == buffer1)
			{
				efree(buffer);
				RETURN_NULL();
			}
			base64_encode(buffer, buffer1, size);
			char *show = (char *)emalloc(size * 1.5 +22);
			strcpy(show, "data:image/bmp;base64,");
			strcat(show, buffer1);
			efree(buffer);
			efree(buffer1);
			remove(filePath);
			RETURN_STRING(show);
		}
		else {
			RETURN_BOOL(1);
		}
	}
	else {
		RETURN_BOOL(0);
	}
}



/* }}} */
/* The previous line is meant for vim and emacs, so it can correctly fold and
   unfold functions in source code. See the corresponding marks just before
   function definition, where the functions purpose is also documented. Please
   follow this convention for the convenience of others editing your code.
*/


/* {{{ php_scarecrow_init_globals
 */
/* Uncomment this function if you have INI entries
static void php_scarecrow_init_globals(zend_scarecrow_globals *scarecrow_globals)
{
	scarecrow_globals->global_value = 0;
	scarecrow_globals->global_string = NULL;
}
*/
/* }}} */
zend_bool php_scarecrow_autoglobal_callback()
{
	zval *sample4_val;
	int i;
	sample4_val = (zval *)emalloc(sizeof(zval));
	array_init(sample4_val);

	add_next_index_string(sample4_val, "showAuthor");
	add_next_index_string(sample4_val, "createQrencode");
	add_next_index_string(sample4_val, "funcInfo");

	zend_string *var_name = zend_string_init("_SCARECROW", sizeof("_SCARECROW") - 1, 0);
	zend_hash_update_ind(&EG(symbol_table), var_name, sample4_val);
	efree(sample4_val);
	return 0;
}

PHP_FUNCTION(funcInfo)
{
	int LEN = 3;
	char *arg = NULL;
	char *funcListName[] = {"showAuthor", "createQrencode", "$_SCARECROW"};
	size_t arg_len;
	if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &arg, &arg_len) == FAILURE) {
		return;
	}

	for (int i = 0; i < LEN; i++) {
		if (strcmp(funcListName[i], arg) == 0) {
			RETURN_STRING(getFunctionInfo(i));
		}
	}
	RETURN_NULL();
	//strg = strpprintf(0, "Congratulations! You have successfully modified ext/%.78s/config.m4. Module %.78s is now compiled into PHP.", "scarecrow", arg);
	//strg = strpprintf(0, Z_STRVAL_P(str));
	//RETURN_STR(strg);
}

char* getFunctionInfo(int iCnt)
{
	char *rel;
	switch (iCnt)
	{
	case 0:
		rel = "showAuthor(): Display Scarecrow Extended Author Information.";
		break;
	case 1:
		rel = "createQrencode($str, $isBaoCun, $filePath): Create a two-dimensional code, $str for the string content to be included, $isBaoCun Whether to save files in BMP format value:0 or 1, $filePath if $isBaoCun value is 1 this path is xxx.bmp file path.";
		break;
	case 2:
		rel = "$_SCARECROW: Scarecrow defined hyperglobal variables that show what methods Scarecrow has.";
		break;
	default:
		rel = "No relevant function information was found!";
		break;
	}
	return rel;
}

/* {{{ PHP_MINIT_FUNCTION
 */

PHP_MINIT_FUNCTION(scarecrow)
{

	/* If you have INI entries, uncomment these lines
	REGISTER_INI_ENTRIES();
	*/
	//注册加载全局php.ini配置文件
	REGISTER_INI_ENTRIES();
	zend_register_auto_global(zend_string_init("_SCARECROW", sizeof("_SCARECROW") - 1, 1), 0, php_scarecrow_autoglobal_callback);
	REGISTER_STRING_CONSTANT("SCARECROW_VERSION","1.0", CONST_CS | CONST_PERSISTENT);
	return SUCCESS;
}
/* }}} */



/* {{{ PHP_MSHUTDOWN_FUNCTION
 */
PHP_MSHUTDOWN_FUNCTION(scarecrow)
{
	/* uncomment this line if you have INI entries
	UNREGISTER_INI_ENTRIES();
	*/
	//销毁配置文件的缓存
	UNREGISTER_INI_ENTRIES();
	return SUCCESS;
}
/* }}} */

/* Remove if there's nothing to do at request start */
/* {{{ PHP_RINIT_FUNCTION
 */
PHP_RINIT_FUNCTION(scarecrow)
{
#if defined(COMPILE_DL_SCARECROW) && defined(ZTS)
	ZEND_TSRMLS_CACHE_UPDATE();
#endif
	return SUCCESS;
}
/* }}} */

/* Remove if there's nothing to do at request end */
/* {{{ PHP_RSHUTDOWN_FUNCTION
 */
PHP_RSHUTDOWN_FUNCTION(scarecrow)
{
	return SUCCESS;
}
/* }}} */

/* {{{ PHP_MINFO_FUNCTION
 */
PHP_MINFO_FUNCTION(scarecrow)
{
	//注意这个每一列展示必须是char *格式
	char sex[5];
	sprintf(sex, "%s", INI_INT("scarecrow.sex") ==1?"boy":"girl");
	php_info_print_table_start();
	php_info_print_table_header(2, "scarecrow list", "enabled");
	php_info_print_table_row(2,"Scarecrow.Version", PHP_SCARECROW_VERSION);
	php_info_print_table_row(2, "Scarecrow.is.name", INI_STR("scarecrow.name"));
	php_info_print_table_row(2, "Scarecrow.is.ShuaiGe", INI_STR("scarecrow.isshuaige"));
	php_info_print_table_row(2, "Scarecrow.is.age", INI_STR("scarecrow.age"));
	php_info_print_table_row(2, "Scarecrow.is.sex", sex);
	php_info_print_table_row(2, "Scarecrow.is.address", INI_STR("scarecrow.address"));
	php_printf("<tr>"
            "<td class=\"v\">Scarecrow</td>"
            "<td class=\"v\">"
            "<a href=\"http://127.0.0.1\""
            " alt=\"Scarecrow Love You\">"
            "<img src=\"http://www.scarecrow.top/tx.png\" />"
		"</a></td></tr>");
	php_info_print_table_end();
	/* Remove comments if you have entries in php.ini
	DISPLAY_INI_ENTRIES();
	*/
}
/* }}} */

/* {{{ scarecrow_functions[]
 *
 * Every user visible function must have an entry in scarecrow_functions[].
 */
const zend_function_entry scarecrow_functions[] = {
	PHP_FE(showAuthor, NULL)		/* For testing, remove later. */
	PHP_FE(createQrencode, NULL)
	PHP_FE(funcInfo, scarecrow_fucinfo_name)
	PHP_FE_END	/* Must be the last line in scarecrow_functions[] */
};
/* }}} */

/* {{{ scarecrow_module_entry
 */
zend_module_entry scarecrow_module_entry = {
	STANDARD_MODULE_HEADER,
	"scarecrow",
	scarecrow_functions,
	PHP_MINIT(scarecrow),
	PHP_MSHUTDOWN(scarecrow),
	PHP_RINIT(scarecrow),		/* Replace with NULL if there's nothing to do at request start */
	PHP_RSHUTDOWN(scarecrow),	/* Replace with NULL if there's nothing to do at request end */
	PHP_MINFO(scarecrow),
	PHP_SCARECROW_VERSION,
	STANDARD_MODULE_PROPERTIES
};
/* }}} */

#ifdef COMPILE_DL_SCARECROW
#ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
#endif
ZEND_GET_MODULE(scarecrow)
#endif

/*
 * Local variables:
 * tab-width: 4
 * c-basic-offset: 4
 * End:
 * vim600: noet sw=4 ts=4 fdm=marker
 * vim<600: noet sw=4 ts=4
 */
